docs(migration): close v1-to-v2 guide gaps found while migrating sample dependents#2392
Conversation
…ion sweep Adds staged-migration ordering, monorepo workspace-member dependency rules, registry-availability notes for the alpha window, the zod compile-time vs runtime symptom split, the completable optional-nesting caveat, gateway inbound error reconstruction with its limits, repo-local tooling that encodes the v1 package name, HeadersInit send-side clarification, the published-alpha error-code qualifier, the InMemoryTransport linked-pair rule, malformed inbound frame behavior, spec-form notification handler examples, OAuth discovery-state and connect-time retry coverage, transport compatibility and unchanged-API bullets, stdio write-failure and session-header notes, third-party dependency guidance, timeout re-baselining relief with per-era cancel-signal qualifiers, and the manifest-handling section matching the codemod's nearest-manifest swap and workspace-member report.
|
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
…loseSSE gating note Two corrections from review: v1-imported and v2-imported processes negotiate through the ordinary 2025-era initialize handshake and settle on the newest revision both packages support (the previous text hardcoded 2025-06-18, which neither side selects today), and ctx.http?.closeSSE is populated only when the transport has an eventStore AND the client's negotiated protocol version supports resumable close — an eventStore transport serving an older client still leaves it undefined.
Adds the navigation layer the guide was missing: a symptom index mapping literal compiler/runtime diagnostics to their sections, a by-situation router, a full-depth table of contents, and a closing verification checklist assembling the done-criteria greps. Splits the largest sections by symptom (the zod floor gets its own findable heading), collapses the duplicated codemod-coverage top matter into one routing layer, moves content documented only in routing bullets into the sections they point at, and gates trial-specific edge cases behind one-glance applicability conditions. Factual corrections: the two client-conformance checklists are unified into one canonical superset; the unchanged-APIs lead no longer claims import-path-only changes; published-alpha caveats are deduplicated and stamped with a greppable marker; the hoisted-monorepo paragraph now matches the codemod's actual behavior; and a section for library authors that peer-depend on the SDK fills the one gap a cold-reader probe could not answer. No behavioral guidance was removed; relocated text moves verbatim.
…2 guide" This reverts commit f64928b.
Completes the OAuthClientProvider conformance checklist with the two obligations the 2026-07-28 guide lists (discovery-state persistence and the insufficient-scope choice), fixes the unchanged-APIs lead to match its own entries, aligns the hoisted-monorepo guidance with the codemod's actual root rewrite, adds a short section for library authors that peer-depend on the SDK, and corrects two notes in the 2026-07-28 guide.
There was a problem hiding this comment.
Additional findings (outside current diff — PR may have been updated during review):
-
🟡
docs/migration/support-2026-07-28.md:486-491— The claim that "the exported*Schemaconstants validate the neutral model and reject it as an unknown key" overgeneralizes: onlyEmptyResultSchemais strict (ResultSchema.strict()), whileResultSchemaitself and the other result schemas listed in this bullet (CallToolResultSchema,GetPromptResultSchema, …) are loose-passthroughResultSchema.extend(...)builds, so parsing a frame carryingresultTypewith them succeeds and keeps the field. Suggest scoping the rejection claim toEmptyResultSchema(matching the guide's own wire-codecs table, which says guards "validate neutral shapes (loose passthrough)") or restoring the previous neutral wording.Extended reasoning...
What the bug is. The rewritten bullet under "Wire-only members hidden from public types" (docs/migration/support-2026-07-28.md, lines 486–491) lists
Result,CallToolResult,GetPromptResultas examples and then states that "the exported*Schemaconstants validate the neutral model and reject it as an unknown key." The plural subject ("the exported*Schemaconstants") in a bullet that just enumerated those result types reads as a claim about all of them — but the rejection behavior only exists forEmptyResultSchema.What the code actually does. In
packages/core-internal/src/types/schemas.ts:ResultSchemaisz.looseObject({...})(line 92), with a comment explicitly noting thatresultTypeis deliberately NOT modeled in the neutral schemas — it lives only inside the 2026-era wire codec.EmptyResultSchema = ResultSchema.strict()(line 180) is the only strict result schema; it alone rejects unknown keys such asresultType.- Every other exported result schema —
GetPromptResultSchema(line 1229),ListToolsResultSchema(line 1371),CallToolResultSchema(line 1378),CreateMessageResultSchema, etc. — is built withResultSchema.extend(...)(orPaginatedResultSchema.extend(...)), which retains the loose catchall in zod 4.
Step-by-step proof. Take a raw 2026-era wire frame's result object:
{ resultType: 'complete', content: [{ type: 'text', text: 'hi' }] }. (1)CallToolResultSchema.parse(obj)succeeds —CallToolResultSchemaisResultSchema.extend({ content: ..., ... }), and the loose base passesresultTypethrough unchanged, so the parsed value still carriesresultType: 'complete'. (2) The same is true forGetPromptResultSchema,ListToolsResultSchema, and the rest. (3) OnlyEmptyResultSchema.parse({ resultType: 'complete' })throws, because.strict()rejects unknown keys. So the documented behavior — rejection as an unknown key — holds for exactly one of the schemas the bullet's subject covers.Why it matters. This bullet is targeted at v2-alpha migrators who previously read
resultTypedirectly. A migrator who validates raw wire frames with e.g.CallToolResultSchemaand trusts this sentence will expect a parse failure on a frame carryingresultType(and may rely on that for traffic classification or sanitization); the parse passes and the field flows through. The sentence also conflicts with the same guide's own wire-codecs table a few lines up (line ~463), whose last row says guards/schemas "validate neutral shapes (loose passthrough); validate raw wire traffic with a transport-level parse." The pre-PR wording ("The wire schemas keep parsing it, and the protocol layer consumes it before results reach your code") made no rejection claim, so this inaccuracy is introduced by the diff. The trailing parenthetical pointing to "theEmptyResultSchemarow" softens but does not scope the plural-subject sentence.Why nothing else catches it.
docs:checkand snippet sync validate links and code blocks, not prose claims about schema strictness, and no verifier objected — all four confirmations independently checked schemas.ts and agreed.How to fix. Scope the claim to the one strict schema, e.g.: "…the exported
*Schemaconstants validate the neutral model and pass unknown keys through — onlyEmptyResultSchemarejectsresultTypeas an unknown key (theEmptyResultSchemarow in the Per-era wire codecs table)." Or simply restore the previous neutral wording. One-clause change, docs only.
Expands the v1→v2 migration guide with everything learned from migrating a bunch of sample dependents (CLI tools, web apps, gateway services, and monorepos of various shapes) using only the guide, the codemod, and the installed typings.
Motivation and Context
Running clean-room migrations of realistic dependents surfaces the questions the guide doesn't answer yet. Every place a migrator had to stop and figure something out became a guide addition. Highlights:
InMemoryTransportlinked pairs, notification-handler forms, typedtools/listreturns, OAuth discovery state, timeout re-baseliningAlso corrects a handful of existing claims that turned out to be inaccurate when checked against source (transport error-message comparison, registry availability, workspace-member wording).
How Has This Been Tested?
Each addition was verified against the SDK source at this branch's base commit before being written.
docs:checkand the snippet sync pass.Breaking Changes
None — documentation only.
Types of changes
Checklist
Additional context
Companion to the codemod PR from the same migration trials; the two are independent and can land in either order.